UNPKG

@lobehub/chat

Version:

Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.

601 lines (535 loc) • 15.1 kB
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import type { Generation, GenerationBatch } from '@/types/generation'; // Import functions for testing import { DEFAULT_MAX_ITEM_WIDTH, getAspectRatio, getImageDimensions, getThumbnailMaxWidth, } from './utils'; describe('getImageDimensions', () => { // Mock base generation object const baseGeneration: Generation = { id: 'test-gen-id', seed: 12345, createdAt: new Date(), asyncTaskId: null, task: { id: 'task-id', status: 'success' as any, }, }; describe('with asset dimensions', () => { it('should return width, height and aspect ratio from asset', () => { const generation: Generation = { ...baseGeneration, asset: { type: 'image', width: 1920, height: 1080, }, }; const result = getImageDimensions(generation); expect(result).toEqual({ width: 1920, height: 1080, aspectRatio: '1920 / 1080', }); }); it('should prioritize asset even when other sources exist', () => { const generation: Generation = { ...baseGeneration, asset: { type: 'image', width: 800, height: 600, }, }; const generationBatch: GenerationBatch = { id: 'batch-id', provider: 'test', model: 'test-model', prompt: 'test prompt', width: 1024, height: 1024, config: { prompt: 'test', width: 512, height: 512, }, createdAt: new Date(), generations: [], }; const result = getImageDimensions(generation, generationBatch); expect(result).toEqual({ width: 800, height: 600, aspectRatio: '800 / 600', }); }); }); describe('with config dimensions', () => { it('should return dimensions from config when asset is not available', () => { const generation: Generation = { ...baseGeneration, asset: null, }; const generationBatch: GenerationBatch = { id: 'batch-id', provider: 'test', model: 'test-model', prompt: 'test prompt', config: { prompt: 'test', width: 1024, height: 768, }, createdAt: new Date(), generations: [], }; const result = getImageDimensions(generation, generationBatch); expect(result).toEqual({ width: 1024, height: 768, aspectRatio: '1024 / 768', }); }); }); describe('with batch top-level dimensions', () => { it('should return dimensions from batch when config is not available', () => { const generation: Generation = { ...baseGeneration, asset: null, }; const generationBatch: GenerationBatch = { id: 'batch-id', provider: 'test', model: 'test-model', prompt: 'test prompt', width: 1280, height: 720, createdAt: new Date(), generations: [], }; const result = getImageDimensions(generation, generationBatch); expect(result).toEqual({ width: 1280, height: 720, aspectRatio: '1280 / 720', }); }); }); describe('with size parameter', () => { it('should parse dimensions from size parameter', () => { const generation: Generation = { ...baseGeneration, asset: null, }; const generationBatch: GenerationBatch = { id: 'batch-id', provider: 'test', model: 'test-model', prompt: 'test prompt', config: { prompt: 'test', size: '1920x1080', }, createdAt: new Date(), generations: [], }; const result = getImageDimensions(generation, generationBatch); expect(result).toEqual({ width: 1920, height: 1080, aspectRatio: '1920 / 1080', }); }); it('should ignore size when it is "auto"', () => { const generation: Generation = { ...baseGeneration, asset: null, }; const generationBatch: GenerationBatch = { id: 'batch-id', provider: 'test', model: 'test-model', prompt: 'test prompt', config: { prompt: 'test', size: 'auto', aspectRatio: '16:9', }, createdAt: new Date(), generations: [], }; const result = getImageDimensions(generation, generationBatch); expect(result).toEqual({ width: null, height: null, aspectRatio: '16 / 9', }); }); }); describe('with aspectRatio parameter only', () => { it('should return aspect ratio without dimensions', () => { const generation: Generation = { ...baseGeneration, asset: null, }; const generationBatch: GenerationBatch = { id: 'batch-id', provider: 'test', model: 'test-model', prompt: 'test prompt', config: { prompt: 'test', aspectRatio: '16:9', }, createdAt: new Date(), generations: [], }; const result = getImageDimensions(generation, generationBatch); expect(result).toEqual({ width: null, height: null, aspectRatio: '16 / 9', }); }); it('should handle various aspect ratio formats', () => { const testCases = [ { aspectRatio: '1:1', expected: '1 / 1' }, { aspectRatio: '4:3', expected: '4 / 3' }, { aspectRatio: '16:9', expected: '16 / 9' }, { aspectRatio: '21:9', expected: '21 / 9' }, ]; testCases.forEach(({ aspectRatio, expected }) => { const generation: Generation = { ...baseGeneration, asset: null, }; const generationBatch: GenerationBatch = { id: 'batch-id', provider: 'test', model: 'test-model', prompt: 'test prompt', config: { prompt: 'test', aspectRatio, }, createdAt: new Date(), generations: [], }; const result = getImageDimensions(generation, generationBatch); expect(result.aspectRatio).toBe(expected); }); }); }); describe('edge cases', () => { it('should return all null when no dimensions are available', () => { const generation: Generation = { ...baseGeneration, asset: null, }; const result = getImageDimensions(generation); expect(result).toEqual({ width: null, height: null, aspectRatio: null, }); }); it('should handle partial asset dimensions', () => { const generation: Generation = { ...baseGeneration, asset: { type: 'image', width: 1920, // height is missing }, }; const generationBatch: GenerationBatch = { id: 'batch-id', provider: 'test', model: 'test-model', prompt: 'test prompt', config: { prompt: 'test', width: 1024, height: 768, }, createdAt: new Date(), generations: [], }; const result = getImageDimensions(generation, generationBatch); expect(result).toEqual({ width: 1024, height: 768, aspectRatio: '1024 / 768', }); }); it('should handle invalid size format', () => { const generation: Generation = { ...baseGeneration, asset: null, }; const generationBatch: GenerationBatch = { id: 'batch-id', provider: 'test', model: 'test-model', prompt: 'test prompt', config: { prompt: 'test', size: 'invalid-format', }, createdAt: new Date(), generations: [], }; const result = getImageDimensions(generation, generationBatch); expect(result).toEqual({ width: null, height: null, aspectRatio: null, }); }); it('should handle invalid aspectRatio format', () => { const generation: Generation = { ...baseGeneration, asset: null, }; const generationBatch: GenerationBatch = { id: 'batch-id', provider: 'test', model: 'test-model', prompt: 'test prompt', config: { prompt: 'test', aspectRatio: 'invalid-format', }, createdAt: new Date(), generations: [], }; const result = getImageDimensions(generation, generationBatch); expect(result).toEqual({ width: null, height: null, aspectRatio: null, }); }); it('should handle zero dimensions', () => { const generation: Generation = { ...baseGeneration, asset: { type: 'image', width: 0, height: 0, }, }; const result = getImageDimensions(generation); expect(result).toEqual({ width: null, height: null, aspectRatio: null, }); }); }); }); describe('getAspectRatio (isolated unit testing)', () => { const mockGeneration: Generation = { id: 'test-gen-id', seed: 12345, createdAt: new Date(), asyncTaskId: null, task: { id: 'task-id', status: 'success' as any, }, }; const mockGenerationBatch: GenerationBatch = { id: 'test-batch-id', provider: 'test-provider', model: 'test-model', prompt: 'test prompt', createdAt: new Date(), generations: [], }; beforeEach(() => { vi.clearAllMocks(); }); it('should return aspectRatio from getImageDimensions when dimensions have aspectRatio', () => { // Test the actual implementation directly with mock data const mockGen: Generation = { ...mockGeneration, asset: { type: 'image', width: 1920, height: 1080, }, }; const result = getAspectRatio(mockGen); expect(result).toBe('1920 / 1080'); }); it('should return default "1 / 1" when no dimensions are available', () => { const result = getAspectRatio(mockGeneration, mockGenerationBatch); expect(result).toBe('1 / 1'); }); it('should work with different aspectRatio sources', () => { const mockBatch: GenerationBatch = { id: 'test-batch', provider: 'test-provider', model: 'test-model', prompt: 'test prompt', createdAt: new Date(), generations: [], config: { prompt: 'test prompt', aspectRatio: '16:9', }, }; const result = getAspectRatio(mockGeneration, mockBatch); expect(result).toBe('16 / 9'); }); }); describe('getThumbnailMaxWidth (isolated unit testing)', () => { const mockGeneration: Generation = { id: 'test-gen-id', seed: 12345, createdAt: new Date(), asyncTaskId: null, task: { id: 'task-id', status: 'success' as any, }, }; const mockGenerationBatch: GenerationBatch = { id: 'test-batch-id', provider: 'test-provider', model: 'test-model', prompt: 'test prompt', createdAt: new Date(), generations: [], }; // Mock window.innerHeight for tests const originalWindow = global.window; beforeEach(() => { vi.clearAllMocks(); Object.defineProperty(global, 'window', { writable: true, value: { innerHeight: 800, }, }); }); afterEach(() => { global.window = originalWindow; }); it('should return DEFAULT_MAX_ITEM_WIDTH when no dimensions available', () => { const result = getThumbnailMaxWidth(mockGeneration, mockGenerationBatch); expect(result).toBe(DEFAULT_MAX_ITEM_WIDTH); }); it('should return DEFAULT_MAX_ITEM_WIDTH when width is missing', () => { const mockGen: Generation = { ...mockGeneration, // No asset with width/height, should fall back to default }; const result = getThumbnailMaxWidth(mockGen); expect(result).toBe(DEFAULT_MAX_ITEM_WIDTH); }); it('should return DEFAULT_MAX_ITEM_WIDTH when height is missing', () => { const mockGen: Generation = { ...mockGeneration, // No asset with valid dimensions }; const result = getThumbnailMaxWidth(mockGen); expect(result).toBe(DEFAULT_MAX_ITEM_WIDTH); }); it('should calculate width based on screen height constraint', () => { const mockGen: Generation = { ...mockGeneration, asset: { type: 'image', width: 300, height: 200, }, }; // aspectRatio = 300/200 = 1.5 // maxScreenHeight = 800/2 = 400 // maxWidthFromHeight = 400 * 1.5 = 600 // maxReasonableWidth = 200 * 2 = 400 // min(600, 400) = 400 const result = getThumbnailMaxWidth(mockGen); expect(result).toBe(400); }); it('should apply maxReasonableWidth limit', () => { const mockGen: Generation = { ...mockGeneration, asset: { type: 'image', width: 600, height: 200, }, }; // aspectRatio = 600/200 = 3 // maxScreenHeight = 800/2 = 400 // maxWidthFromHeight = 400 * 3 = 1200 // maxReasonableWidth = 200 * 2 = 400 // min(1200, 400) = 400 const result = getThumbnailMaxWidth(mockGen); expect(result).toBe(400); }); it('should use screen height constraint when smaller', () => { const mockGen: Generation = { ...mockGeneration, asset: { type: 'image', width: 200, height: 400, }, }; // aspectRatio = 200/400 = 0.5 // maxScreenHeight = 800/2 = 400 // maxWidthFromHeight = 400 * 0.5 = 200 // maxReasonableWidth = 200 * 2 = 400 // min(200, 400) = 200 const result = getThumbnailMaxWidth(mockGen); expect(result).toBe(200); }); it('should handle different window.innerHeight values', () => { Object.defineProperty(global, 'window', { writable: true, value: { innerHeight: 600, }, }); const mockGen: Generation = { ...mockGeneration, asset: { type: 'image', width: 400, height: 200, }, }; // aspectRatio = 400/200 = 2 // maxScreenHeight = 600/2 = 300 // maxWidthFromHeight = 300 * 2 = 600 // maxReasonableWidth = 200 * 2 = 400 // min(600, 400) = 400 const result = getThumbnailMaxWidth(mockGen); expect(result).toBe(400); }); it('should round calculated width correctly', () => { const mockGen: Generation = { ...mockGeneration, asset: { type: 'image', width: 512, height: 1000, }, }; // aspectRatio = 512/1000 = 0.512 // maxScreenHeight = 800/2 = 400 // maxWidthFromHeight = Math.round(400 * 0.512) = Math.round(204.8) = 205 // maxReasonableWidth = 200 * 2 = 400 // min(205, 400) = 205 const result = getThumbnailMaxWidth(mockGen); expect(result).toBe(205); }); });